1use super::RealTimeData;
2use bitfields::bitfield;
3use num_enum::{IntoPrimitive, TryFromPrimitive};
4use std::ffi::{CStr, c_char};
5
6#[derive(Debug, Copy, Clone)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct GroupData {
9 pub squad_markers: [[f32; 3]; 8],
11
12 pub group_type: Result<GroupType, u32>,
14
15 pub group_member_count: u32,
17}
18
19impl GroupData {
20 pub unsafe fn read(data: *const RealTimeData) -> Self {
25 unsafe {
26 Self {
27 squad_markers: (*data).squad_markers,
28 group_type: (*data).group_type.try_into(),
29 group_member_count: (*data).group_member_count,
30 }
31 }
32 }
33}
34
35#[derive(
36 Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TryFromPrimitive, IntoPrimitive,
37)]
38#[num_enum(error_type(name = u32, constructor = From::from))]
39#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
40#[cfg_attr(
41 feature = "strum",
42 derive(
43 strum::AsRefStr,
44 strum::Display,
45 strum::EnumCount,
46 strum::EnumIter,
47 strum::IntoStaticStr,
48 strum::VariantArray,
49 strum::VariantNames
50 )
51)]
52#[repr(u32)]
53pub enum GroupType {
54 None,
55 Party,
56 RaidSquad,
57 Squad,
58}
59
60#[derive(Debug, Clone)]
65#[repr(C)]
66pub struct GroupMember {
67 account_name: [c_char; 140],
69
70 character_name: [c_char; 140],
72
73 pub subgroup: u32,
78
79 pub profession: u32,
83
84 pub elite_specialization: u32,
88
89 flags: GroupMemberFlags,
91}
92
93impl GroupMember {
94 #[inline]
96 pub fn to_owned(&self) -> GroupMemberOwned {
97 self.into()
98 }
99
100 #[inline]
102 pub const fn account_name_ptr(&self) -> *const c_char {
103 self.account_name.as_ptr()
104 }
105
106 #[inline]
108 pub fn account_name_cstr(&self) -> &CStr {
109 unsafe { CStr::from_ptr(self.account_name.as_ptr()) }
110 }
111
112 #[inline]
114 pub fn account_name(&self) -> String {
115 self.account_name_cstr().to_string_lossy().into_owned()
116 }
117
118 #[inline]
120 pub const fn character_name_ptr(&self) -> *const c_char {
121 self.character_name.as_ptr()
122 }
123
124 #[inline]
126 pub fn character_name_cstr(&self) -> &CStr {
127 unsafe { CStr::from_ptr(self.character_name.as_ptr()) }
128 }
129
130 #[inline]
132 pub fn character_name(&self) -> String {
133 self.character_name_cstr().to_string_lossy().into_owned()
134 }
135
136 #[inline]
138 pub const fn flags(&self) -> GroupMemberFlags {
139 self.flags
140 }
141
142 #[inline]
144 pub const fn is_self(&self) -> bool {
145 self.flags.is_self()
146 }
147
148 #[inline]
150 pub const fn is_in_instance(&self) -> bool {
151 self.flags.is_in_instance()
152 }
153
154 #[inline]
156 pub const fn is_commander(&self) -> bool {
157 self.flags.is_commander()
158 }
159
160 #[inline]
162 pub const fn is_lieutenant(&self) -> bool {
163 self.flags.is_lieutenant()
164 }
165}
166
167#[bitfield(u32)]
168#[derive(Copy, Clone, PartialEq, Eq)]
169#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
170pub struct GroupMemberFlags {
171 pub is_self: bool,
172 pub is_in_instance: bool,
173 pub is_commander: bool,
174 pub is_lieutenant: bool,
175
176 #[bits(28)]
177 _padding: u32,
178}
179
180#[derive(Debug, Clone)]
182#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
183pub struct GroupMemberOwned {
184 pub account_name: String,
186
187 pub character_name: String,
189
190 pub subgroup: u32,
192
193 pub profession: u32,
195
196 pub elite_specialization: u32,
198
199 pub is_self: bool,
201
202 pub is_in_instance: bool,
204
205 pub is_commander: bool,
207
208 pub is_lieutenant: bool,
210}
211
212impl From<&GroupMember> for GroupMemberOwned {
213 fn from(member: &GroupMember) -> Self {
214 Self {
215 account_name: member.account_name(),
216 character_name: member.character_name(),
217 subgroup: member.subgroup,
218 profession: member.profession,
219 elite_specialization: member.elite_specialization,
220 is_self: member.is_self(),
221 is_in_instance: member.is_in_instance(),
222 is_commander: member.is_commander(),
223 is_lieutenant: member.is_lieutenant(),
224 }
225 }
226}